package DRC.DRModbus;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;

import DRC.DRCDB;
import DRC.channel;
import DRC.channel4collect;
import DRC.dataItem;
import DRC.dataItem4collect;
import DRCOMM.dr_util;
import DRCOMM.record_data_set;

public class DRModbus_TCP_Slave extends Thread{

    // 定义常量
    final public static int REGISTER_TYPE_COILS = 1;
    final public static int REGISTER_TYPE_DISCRETE_INPUTS = 2;
    final public static int REGISTER_TYPE_HOLDING_REGISTERS = 3;
    final public static int REGISTER_TYPE_INPUT_REGISTERS = 4;

    public ServerSocket server;

    int channel_id;
    public DRCDB drcdb;
    public String host = "";
    public int port = 502;
    public int type = 0;
    public int data_type=0;
    public int channel4collect_id = 0;
    public int runcount=0;
    public boolean runMark=false;
    public int buffSize=1024;
    // public List<Byte> recive_buff=new ArrayList<Byte>();
    // public List<Byte> send_buff=new ArrayList<Byte>();
    public byte[] recive_buff=new byte[2048];
    public byte[] send_buff=new byte[2048];

    private static String logPrefix = "./log/Modbus/ModbusTCPSlave_";

    public static ArrayList<channel> channels=null;
    public static ArrayList<channel4collect> channels4collect=null;

    public DRModbus_TCP_Slave(DRCDB drcdb){
        this.drcdb=drcdb;
    }

    public DRModbus_TCP_Slave(DRCDB drcdb,int port){
        this.drcdb=drcdb;
        try {
            this.bindPort(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public DRModbus_TCP_Slave(DRCDB drcdb,int port,int channel_id){
        this.drcdb=drcdb;
        this.channel_id=channel_id;
        try {
            this.bindPort(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void bindPort(int port) throws IOException{
        this.server=new ServerSocket(port);
        // this.server.setSoTimeout(10000);
        this.port=port;
    }

    public void set_channel_type(int type,int channel4collect_id,int data_type){
        this.type=type;
        this.channel4collect_id=channel4collect_id;
        this.data_type=data_type;
    }

    // protected void finalize() throws IOException{
    //     this.server.close();
    // }

    public void releasePort() throws IOException{
        this.server.close();
    }

    public void set_drcdb(DRCDB drcdb){
        this.drcdb=drcdb;
    }

    @Override
    public void run(){
        while(true){
            try {
                System.out.println("等待远程连接，端口号为：" + this.server.getLocalPort() + "...");
                Socket st = this.server.accept();
                System.out.println("远程主机地址：" + st.getRemoteSocketAddress());

                int data_length;
                String str=null;
                //获取Socket的输出流，用来向客户端发送数据
                DataOutputStream out = new DataOutputStream (st.getOutputStream());
                //获取Socket的输入流，用来接收从客户端发送过来的数据
                // BufferedReader reader = new BufferedReader(new InputStreamReader(st.getInputStream(), "UTF-8"));
                DataInputStream in = new DataInputStream(st.getInputStream());
                int function_code;
                byte[] result=null;
                while(true){
                    try {
                        // 获取接收字节长度
                        data_length=in.read(this.recive_buff);
                        //请求报文日志
                        int receiveLength = dr_util.byteToInt(recive_buff[5])+6;
                        byte[] trueReceive = new byte[receiveLength];
                        System.arraycopy(recive_buff,0,trueReceive,0,receiveLength);
                        write_log(0,"127.0.0.1",String.valueOf(port),trueReceive,receiveLength);
                        if(data_length==-1)break;
                        // 分解功能码
                        function_code=this.recive_buff[7];
                        switch(function_code){
                            case 0x01:
                                result=this.modbus_tcp_01_slave(this.recive_buff);
                                break;
                            case 0x02:
                                result=this.modbus_tcp_02_slave(this.recive_buff);
                                break;
                            case 0x03:
                                result=this.modbus_tcp_03_slave(this.recive_buff);
                                break;
                            case 0x04:
                                result=this.modbus_tcp_04_slave(this.recive_buff);
                                break;
                            case 0x05:
                                result=this.modbus_tcp_05_slave(this.recive_buff);
                                break;
                            case 0x06:
                                result=this.modbus_tcp_06_slave(this.recive_buff);
                                break;
                            case 0x0F:
                                result=this.modbus_tcp_0F_slave(this.recive_buff);
                                break;
                            case 0x10:
                                result=this.modbus_tcp_10_slave(this.recive_buff);
                                break;
                            default:
                        }
                        // 向 Master 端输出响应
                        out.write(result);
                        //回复报文日志
                        write_log(1,"127.0.0.1",String.valueOf(port),result,result.length);
                        // 显示接收、发送内容
                        str=dr_util.bytes2hexstr(this.recive_buff,data_length);
                        System.out.println(String.format("client send message:[%s]",str));
                        str=dr_util.bytes2hexstr(result);
                        System.out.println(String.format("server response message:[%s]",str));                        
                    } catch (Exception e) {
                        System.out.println("Modbus process error!");
                    }
                }
            } catch(SocketTimeoutException s){
                System.out.println("Socket timed out!");
                break;
            }catch(IOException e){
                System.out.println("Socket closed!");
                // e.printStackTrace();
                break;
            }
        }
    }

    public byte[] modbus_tcp_01_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x01){
            int data_index_start=buff[8]*256+buff[9];
            int data_count=buff[10]*256+buff[11];
            byte[] results=null;
            if(this.type==0){
                results=dataItem.readLocalDataItem4bit( mbaph.slave_id,
                    REGISTER_TYPE_COILS, data_index_start, data_count);
            }else if(this.type==1){
                    results=dataItem4collect.readLocalDataItem4bit(this.channel4collect_id,mbaph.slave_id,
                    REGISTER_TYPE_COILS, data_index_start, data_count);
            }else{
                results=read_dataItem2channel2datas4bit(
                    REGISTER_TYPE_COILS, data_index_start, data_count);
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)((results.length+3)/256));
            response_data.add((byte)((results.length+3)%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)results.length);
            for(int i=0;i<results.length;i++){
                response_data.add(results[i]);
            }
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    public byte[] modbus_tcp_02_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x02){
            int data_index_start=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int data_count=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            byte[] results=null;
            if(this.type==0){
                results=dataItem.readLocalDataItem4bit( mbaph.slave_id,
                    REGISTER_TYPE_DISCRETE_INPUTS, data_index_start, data_count);
            }else if(this.type==1){
                    results=dataItem4collect.readLocalDataItem4bit( this.channel4collect_id, mbaph.slave_id,
                    REGISTER_TYPE_DISCRETE_INPUTS, data_index_start, data_count);
            }else{
                results=read_dataItem2channel2datas4bit(
                    REGISTER_TYPE_DISCRETE_INPUTS, data_index_start, data_count);
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)((results.length+3)/256));
            response_data.add((byte)((results.length+3)%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)results.length);
            for(int i=0;i<results.length;i++){
                response_data.add(results[i]);
            }
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    public byte[] modbus_tcp_03_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        float data;
        if(function_code==0x03){
            int data_index_start=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int data_count=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            ArrayList<Float> results=null;
            if(this.type==0){
                if(this.data_type==0){
                    results=dataItem.readLocalDataItem(mbaph.slave_id,
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count);
                }else{
                    results=dataItem.readLocalDataItem(mbaph.slave_id,
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count/2);
                }
            }else if(this.type==1){
                if(this.data_type==0){
                    results=dataItem4collect.readLocalDataItem(this.channel4collect_id, mbaph.slave_id,
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count);
                }else{
                    results=dataItem4collect.readLocalDataItem(this.channel4collect_id, mbaph.slave_id,
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count/2);
                }
            }else{
                // 否则为多通通数据，不再依据寄存器地址，而是根据多通道数据循序重新对应地址
                if(this.data_type==0){
                    results=read_dataItem2channel2datas(
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count);
                }else{
                    results=read_dataItem2channel2datas(
                        REGISTER_TYPE_INPUT_REGISTERS, data_index_start, data_count/2);
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            if(this.data_type==0){
                response_data.add((byte)((results.size()*2+3)/256));
                response_data.add((byte)((results.size()*2+3)%256));
            }else{
                response_data.add((byte)((results.size()*4+3)/256));
                response_data.add((byte)((results.size()*4+3)%256));
            }
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            if(this.data_type==0){
                response_data.add((byte)(results.size()*2));
                for(int i=0;i<results.size();i++){
                    data=results.get(i);
                    if(data>=0) {
                        response_data.add((byte) (Math.floor(data) / 256));
                        response_data.add((byte) (Math.floor(data) % 256));
                    }else{
                        data = 32768+data;
                        response_data.add((byte)((byte)(Math.floor(data)/256)|0x80));
                        response_data.add((byte)(Math.floor(data)%256));
                    }
                }
            }else if(this.data_type==1){
                response_data.add((byte)(results.size()*4));
                int[] value_list;
                for(int i=0;i<results.size();i++){
                    data=results.get(i);
                    value_list=dr_util.float_to_IEEE_STD_754(data);
                    response_data.add((byte)value_list[1]);
                    response_data.add((byte)value_list[0]);
                    response_data.add((byte)value_list[3]);
                    response_data.add((byte)value_list[2]);
                }
            }
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    public byte[] modbus_tcp_04_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        float data;
        if(function_code==0x04){
            int data_index_start=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int data_count=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            ArrayList<Float> results=null;
            if(this.type==0){
                if(this.data_type==0){
                    results=dataItem.readLocalDataItem( mbaph.slave_id,
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count);
                }else{
                    results=dataItem.readLocalDataItem( mbaph.slave_id,
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count/2);
                }
            }else if(this.type==1){
                if(this.data_type==0){
                    results=dataItem4collect.readLocalDataItem( this.channel4collect_id, mbaph.slave_id,
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count);
                }else{
                    results=dataItem4collect.readLocalDataItem( this.channel4collect_id, mbaph.slave_id,
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count/2);
                }
            }else{
                // 否则为多通通数据，不再依据寄存器地址，而是根据多通道数据循序重新对应地址
                if(this.data_type==0){
                    results=read_dataItem2channel2datas(
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count);
                }else{
                    results=read_dataItem2channel2datas(
                        REGISTER_TYPE_HOLDING_REGISTERS, data_index_start, data_count/2);
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            if(this.data_type==0){
                response_data.add((byte)((results.size()*2+3)/256));
                response_data.add((byte)((results.size()*2+3)%256));
            }else{
                response_data.add((byte)((results.size()*4+3)/256));
                response_data.add((byte)((results.size()*4+3)%256));
            }
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            // for(int i=0;i<results.datas.size();i++){
            //     data=Float.parseFloat(results.datas.get(i).get("value"));
            //     response_data.add((byte)(Math.floor(data)/256));
            //     response_data.add((byte)(Math.floor(data)%256));
            // }
            if(this.data_type==0){
                response_data.add((byte)(results.size()*2));
                for(int i=0;i<results.size();i++){
                    data=results.get(i);
                    if(data>=0){
                        response_data.add((byte)(Math.floor(data)/256));
                        response_data.add((byte)(Math.floor(data)%256));
                    }else{
                        data=32768+data;
                        response_data.add((byte)((byte)(Math.floor(data)/256)|0x80));
                        response_data.add((byte)(Math.floor(data)%256));
                    }
                }
            }else if(this.data_type==1){
                response_data.add((byte)(results.size()*4));
                // IEEE754浮点数处理逻辑，需要确定处理条件。    2023年8月21日   罗继东
                // IEEE754浮点数占用4个字节，普通整数占2个字节
                int[] value_list;
                for(int i=0;i<results.size();i++){
                    data=results.get(i);
                    value_list=dr_util.float_to_IEEE_STD_754(data);
                    response_data.add((byte)value_list[1]);
                    response_data.add((byte)value_list[0]);
                    response_data.add((byte)value_list[3]);
                    response_data.add((byte)value_list[2]);
                }
            }
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    public byte[] modbus_tcp_05_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x05){
            int data_index=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int value;
            if(buff[10]==0xFF||buff[10]==-1)
                value=1;
            else
                value=0;
            channel ch = null;
            for (DRC.channel channel : channels) {
                if (channel.channel_id == this.channel_id) {
                    ch = channel;
                    break;
                }
            }
            if(ch!=null) {
                channel4collect c4c = null;
                dataItem4collect di4c = null;
                switch (this.type) {
                    case 0:
                    case 2:
                        di4c = ch.d4cs.get(data_index);
                        break;
                    case 1:
                        c4c = ch.c4c;
                        di4c = c4c.ds4c.get(data_index);
                        break;
                }
                if (di4c != null) {
                    di4c.value = value;
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)(mbaph.length/256));
            response_data.add((byte)(mbaph.length%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)(data_index/256));
            response_data.add((byte)(data_index%256));
            response_data.add((byte)buff[10]);
            response_data.add((byte)buff[11]);
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    public byte[] modbus_tcp_06_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x06){
            int data_index=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int value=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            channel ch = null;
            for (DRC.channel channel : channels) {
                if (channel.channel_id == this.channel_id) {
                    ch = channel;
                    break;
                }
            }
            if(ch!=null) {
                channel4collect c4c = null;
                dataItem4collect di4c = null;
                switch (this.type) {
                    case 0:
                    case 2:
                        di4c = ch.d4cs.get(data_index);
                        break;
                    case 1:
                        c4c = ch.c4c;
                        di4c = c4c.ds4c.get(data_index);
                        break;
                }
                if (di4c != null) {
                    if(value>32768) {
                        di4c.value = value-65536;
                    }else {
                        di4c.value = value;
                    }
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)(mbaph.length/256));
            response_data.add((byte)(mbaph.length%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)(data_index/256));
            response_data.add((byte)(data_index%256));
            response_data.add((byte)(value/256));
            response_data.add((byte)(value%256));
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    // 0F 写多个线圈
    public byte[] modbus_tcp_0F_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x0F){
            int data_index=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int data_count=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            int byte_count=buff[12];
            int value;
            channel ch = null;
            for(int i=0;i<channels.size();i++){
                if(channels.get(i).channel_id==this.channel_id){
                    ch=channels.get(i);
                    break;
                }
            }
            for(int i=0;i<=data_count/8;i++){
                for(int j=0;j<8&&(i*8+j)<data_count;j++){
                    value=(buff[13+i]>>j)&0x01;
                    if(ch!=null) {
                        channel4collect c4c = null;
                        dataItem4collect di4c = null;
                        switch (this.type) {
                            case 0:
                            case 2:
                                di4c = ch.d4cs.get(data_index+i*8+j);
                                break;
                            case 1:
                                c4c = ch.c4c;
                                di4c = c4c.ds4c.get(data_index+i*8+j);
                                break;
                        }
                        if (di4c != null) {
                            di4c.value = value;
                        }
                    }
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)(mbaph.length/256));
            response_data.add((byte)(mbaph.length%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)(data_index/256));
            response_data.add((byte)(data_index%256));
            response_data.add((byte)buff[10]);
            response_data.add((byte)buff[11]);
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    // 10 写多个寄存器
    public byte[] modbus_tcp_10_slave(byte[] buff){
        List<Byte> result=new ArrayList<Byte>();
        MBAPH mbaph=DRModbus_TCP_Slave.parser_MBAPH(buff);
        int function_code=buff[7];
        if(function_code==0x10){
            int data_index=((int)buff[8]&0xff)*256+((int)buff[9]&0xff);
            int data_count=((int)buff[10]&0xff)*256+((int)buff[11]&0xff);
            int byte_count=buff[12];
            channel ch = null;
            for(int i=0;i<channels.size();i++){
                if(channels.get(i).channel_id==this.channel_id){
                    ch=channels.get(i);
                    break;
                }
            }
            for(int i=0;i<=data_count;i++){
                if(data_type==0) {
                    int value = ((int) buff[13 + i * 2] & 0xff) * 256 + ((int) buff[14 + i * 2] & 0xff);
                    if(ch!=null) {
                        channel4collect c4c = null;
                        dataItem4collect di4c = null;
                        switch (this.type) {
                            case 0:
                            case 2:
                                di4c = ch.d4cs.get(data_index+i);
                                break;
                            case 1:
                                c4c = ch.c4c;
                                di4c = c4c.ds4c.get(data_index+i);
                                break;
                        }
                        if (di4c != null) {
                            if(value>32768) {
                                di4c.value = value-65536;
                            }else {
                                di4c.value = value;
                            }
                        }
                    }
                }else {
                    byte[] data=new byte[4];
                    data[0]= (byte) (buff[13+i*4]&0xFF);
                    data[1]= (byte) (buff[14+i*4]&0xFF);
                    data[2]= (byte) (buff[15+i*4]&0xFF);
                    data[3]= (byte) (buff[16+i*4]&0xFF);
                    float value = dr_util.byte4tofloat_b(data);
                    if(ch!=null) {
                        channel4collect c4c = null;
                        dataItem4collect di4c = null;
                        switch (this.type) {
                            case 0:
                            case 2:
                                di4c = ch.d4cs.get(data_index+i);
                                break;
                            case 1:
                                c4c = ch.c4c;
                                di4c = c4c.ds4c.get(data_index+i);
                                break;
                        }
                        if (di4c != null) {
                            di4c.value = value;
                        }
                    }
                }
            }
            List<Byte> response_data=new ArrayList<Byte>();
            response_data.add((byte)(mbaph.event_id/256));
            response_data.add((byte)(mbaph.event_id%256));
            response_data.add((byte)(mbaph.protocol/256));
            response_data.add((byte)(mbaph.protocol%256));
            response_data.add((byte)(mbaph.length/256));
            response_data.add((byte)(mbaph.length%256));
            response_data.add((byte)mbaph.slave_id);
            response_data.add((byte)function_code);
            response_data.add((byte)(data_index/256));
            response_data.add((byte)(data_index%256));
            response_data.add((byte)buff[10]);
            response_data.add((byte)buff[11]);
            result=response_data;
        }
        return dr_util.ListToBytes(result);
    }

    private byte[] read_dataItem2channel2datas4bit(
    int register_type,int start,int length){
        List<Byte> result=new ArrayList<Byte>();
        channel ch=null;
        for(channel c:channels){
            if(this.channel_id==c.channel_id){
                ch=c;
                break;
            }
        }
        if(ch==null)return null;
        byte b;
        if(ch.type==0){
            for(int i=start;i<start+length&&i<ch.dataItems.size();i+=8){
                b=0;
                for(int j=i;j<(i+8)&&j<ch.dataItems.size();j++){
                    if(ch.dataItems.get(j).value==1.0f){
                        b=(byte) ((byte)b|0x01<<(j-i));
                    }
                }
                result.add(b);
            }
        }else if(ch.type==1){
            for(int i=start;i<start+length&&i<ch.c4c.ds4c.size();i+=8){
                b=0;
                for(int j=i;j<(i+8)&&j<ch.c4c.ds4c.size();j++){
                    if(ch.c4c.ds4c.get(j).value==1.0f){
                        b=(byte) ((byte)b|0x01<<(j-i));
                    }
                }
                result.add(b);
            }
        }else{
            for(int i=start;i<start+length&&i<ch.d4cs.size();i+=8){
                b=0;
                for(int j=i;j<(i+8)&&j<ch.d4cs.size();j++){
                    if(ch.d4cs.get(j).value==1.0f){
                        b=(byte) ((byte)b|0x01<<(j-i));
                    }
                }
                result.add(b);
            }
        }
        return dr_util.ListToBytes(result);
    }

    private ArrayList<Float> read_dataItem2channel2datas(int register_type,int start,int length){
        ArrayList<Float> dis=new ArrayList<>();
        ArrayList<dataItem4collect> d4cs=null;
        for(channel ch:channels){
            if(this.channel_id==ch.channel_id){
                d4cs=ch.d4cs;
            }
        }
        if(d4cs==null)return null;
        // 逐个扫描数据点，判断register_type,start是否一致
        for (dataItem4collect di : d4cs) {
            if(register_type==di.register_type&&start==di.address){
                for(int i=0;i<length&&i<d4cs.size();i++){
                    dis.add(d4cs.get(i).value);
                }
            }
        }
        return dis;
    }

    public static MBAPH parser_MBAPH(byte[] buff){
        MBAPH result=new MBAPH();
        // 通过与0xFF避免java把byte值转换为有符号数
        int event_id=(buff[0]&0xFF)*256+(buff[1]&0xFF);
        int protocol=buff[2]*256+buff[3];
        int length=(buff[4]&0xFF)*256+(buff[5]&0xFF);
        int slave_id=(buff[6]&0xFF);
        result.event_id=event_id;
        result.protocol=protocol;
        result.length=length;
        result.slave_id=slave_id;
        return result;
    }

    /**
     * 写入日志函数
     * @param direction 0:接收 1发送
     * @param indestIP  目标IP
     * @param indestPart 目标端口
     * @param data       帧内容
     * @param data_length   帧内容长度
     * @throws IOException
     */
    public static void write_log(int direction,String indestIP,String indestPart,byte[] data,int data_length) throws IOException {
        int logSwitch = Integer.parseInt(DRCDB.read_conf_with_name("log_switch", "conf.ini"));
        if(logSwitch==1) {
            //根据帧内容生成最终的buff，并写入日志文件
            String destIP = indestIP + ":" + indestPart;
            String log;
            if (direction == 0)
                log = destIP + ":RX<<" + dr_util.bytes2hexstr(data, data_length);
            else
                log = destIP + ":TX>>" + dr_util.bytes2hexstr(data, data_length);
            writeLog(log);
        }
    }

    /**
     * 写日志函数
     * @param inStr
     * @throws IOException
     */
    public static void writeLog(String inStr) throws IOException {
        //写入日志函数
        //按日期和日志前缀拼接出日志文件名，向文件尾写入输入的字符串内容
        Date dNow = new Date( );
        SimpleDateFormat ft = new SimpleDateFormat ("yyyyMMdd");

        String logFileName=logPrefix+ft.format(dNow)+".log";

        // 转换为Path对象
        Path logPath = Paths.get(logFileName);
        // 提取目录路径
        Path dirPath = logPath.getParent();
        // 检查目录是否存在，如果不存在则创建
        if (!Files.exists(dirPath)) {
            try {
                Files.createDirectories(dirPath);
                System.out.println("Modbus 目录已创建");
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }

        File logFile = new File(logFileName);
        if(!logFile.exists()){
            logFile.createNewFile();
        }
        FileWriter fileWriter=new FileWriter(logFile,true);
        SimpleDateFormat ft2 = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
        fileWriter.write("["+ft2.format(dNow)+"]"+inStr+"\n");
        fileWriter.close();
    }

    public static void main(String[] args){
        // int port = Integer.parseInt(args[0]);
        DRCDB drcdb=new DRCDB();
        try{
            DRModbus_TCP_Slave ts = new DRModbus_TCP_Slave(drcdb);
            ts.bindPort(502);
            ts.run();
        }catch(IOException e){
            e.printStackTrace();
        }
        // short a=0xFF;
        // System.out.println(String.format("16进制:%X", a&0xf0));
    }

}

class MBAPH{
    
    public int event_id;
    public int protocol;
    public int length;
    public int slave_id;
    
}